import threading
from core.status_logger import LogStatus as CLogger
from core.status_logger import ProgressStatus as CProgress


class Timer(threading.Thread):
    """Call a function after a specified number of seconds:

            t = Timer(30.0, f, args=None, kwargs=None)
            t.start()
            t.cancel()     # stop the timer's action if it's still waiting

    """

    def __init__(self, interval: float, repeat: bool, function, args=None, kwargs=None):
        threading.Thread.__init__(self)
        self.interval = interval
        self.repeat = repeat
        self.function = function
        self.args = args if args is not None else []
        self.kwargs = kwargs if kwargs is not None else {}
        self.finished = threading.Event()
        self.next = threading.Event()

    def cancel(self):
        """Stop the timer if it hasn't finished yet."""
        self.finished.set()
        self.next.set()

    def run(self):
        self.next.clear()
        self.finished.clear()
        while self.repeat:
            self.next.wait(self.interval)
            if not self.finished.is_set():
                self.function(*self.args, **self.kwargs)
            else:
                break


class LogicThread(threading.Thread):
    def __init__(self, logger: CLogger = None, progress: CProgress = None, parent=None):
        threading.Thread.__init__(self)
        self.children = []
        if not isinstance(parent, LogicThread):
            parent = None
        else:
            parent.children.append(self)
        self.logger: CLogger = logger if logger is not None else (
            parent.logger if parent is not None else None
        )
        self.progress: CProgress = progress if progress is not None else (
            parent.progress if parent is not None else None
        )
        self._callback_thread_started = []
        self._callback_thread_over = []
        self._flag_run = threading.Event()
        self._flag_run.clear()
        self._flag_stopped = threading.Event()
        self._flag_stopped.set()
        self._flag_continue = threading.Event()
        self._flag_continue.set()
        pass

    def set_logger_ctrl(self, logger: CLogger):
        self.logger = logger

    def set_progress_ctrl(self, progress: CProgress):
        self.progress = progress

    def add_callback_thread_started(self, func, obj=None, *args):
        self._callback_thread_started.append((func, obj, args,))

    def clear_callback_thread_start(self):
        self._callback_thread_started.clear()

    def delete_callback_thread_start(self, func, obj=None):
        for f in self._callback_thread_started:
            if len(f) > 2 and f[0] == func and f[1] == obj:
                self._callback_thread_started.remove(f)

    def add_callback_thread_over(self, func, obj=None, *args):
        self._callback_thread_over.append((func, obj, args,))

    def clear_callback_thread_over(self):
        self._callback_thread_over.clear()

    def delete_callback_thread_over(self, func, obj=None):
        for f in self._callback_thread_started:
            if len(f) > 2 and f[0] == func and f[1] == obj:
                self._callback_thread_started.remove(f)

    def run(self):
        for f in self._callback_thread_started:
            try:
                if f[1]:
                    f[0](f[1], *f[2])
                else:
                    f[0](*f[2])
            except:
                pass
        try:
            self.execute()
        except Exception as ex:
            self.log_msg("Internal error in <execute>:", CLogger.MsgType.ERROR)
            self.log_msg(str(ex), CLogger.MsgType.ERROR)
        for f in self._callback_thread_over:
            try:
                if f[1]:
                    f[0](f[1], *f[2])
                else:
                    f[0](*f[2])
            except:
                pass

    def execute(self):
        """
        Execute specific operations, rewrite this method.
        """
        pass

    def require_pause(self):
        if self._flag_continue.is_set():
            self._flag_continue.clear()
        for obj in self.children:
            obj.require_pause()

    def require_continue(self):
        if not self._flag_continue.is_set():
            self._flag_continue.set()
        for obj in self.children:
            obj.require_continue()

    def is_paused(self):
        return not self._flag_continue.is_set()

    def require_stop(self):
        if not self._flag_stopped.is_set():
            self._flag_run.clear()
        for obj in self.children:
            obj.require_stop()
        # 防止因暂停导致无法检测停止
        if self.is_paused():
            self.require_continue()

    def wait_stopped(self, timeout=None):
        """等待线程停止(时间:s)"""
        self._flag_stopped.wait(timeout)

    def is_stopped(self):
        return self._flag_stopped.is_set()

    def log_msg(self, msg: str, type: CLogger.MsgType = CLogger.MsgType.DEFAULT):
        if self.logger is not None:
            self.logger.write(msg, type)

    def reset_progress(self):
        if self.progress is not None:
            self.progress.reset_value()

    def increase_progress(self, value):
        if self.progress is not None:
            self.progress.increase(value)

    def update_progress(self, value):
        if self.progress is not None:
            self.progress.set_value(value)


if __name__=="__main__":
    th = LogicThread()
    th.add_callback_thread_started(lambda :print("start"))
    th.add_callback_thread_over(lambda :print("over"))
    th.start()
